/**
 * 使用 class 定义类，使用 constructor 定义构造函数
 * 通过 new 生成新实例的时候，会自动调用构造函数
 **/
class Animal{
	constructor(name){
		this.name = name;
	}
	sayHi(){
		return `My name is ${this.name}`; 
	}
}
let a = new Animal('Jack');
console.log(a.sayHi());   // My name is Jack


/**
 * 类的继承
 * 使用 extends 关键字实现继承，子类中使用 super 关键字来调用父类的构造函数和方法
 **/
class Cat extends Animal{
	constructor(name){
		super(name);   // 调用父类的 constructor(name)
		console.log(this.name);
	}
	sayHi(){
		return 'Meow, ' + super.sayHi(); // 调用父类的 sayHi() 
	}
}

let c = new Cat('Tom');  // Tom
console.log(c.sayHi());  // Meow, My name is Tom


/**
 * 存取器
 * 使用 getter 和 setter 可以改变属性的赋值和读取行为：
 **/
class Animal{
	constructor(name){
		this.name = name;
	}
	get name(){
		return 'Jack';
	}
	set name(value){
		console.log('setter:' + value);
	}
}
let a = new Animal('Kitty');  // setter: Kitty
a.name = 'Tom';   // setter: Tom
console.log(a.name);  // Jack


/**
 * 静态方法
 * 使用 static 修饰符修饰的方法称为静态方法，它们不需要实例化，而是直接通过类来调用：
 **/
class Animal{
	static isAnimal(a){
		return a instanceof Animal;
	}
}
let a = new Animal('Jack');
Animal.isAnimal(a);  // true
a.isAnimal(a);  // TypeError: a.isAnimal is not a function


/**
 * 
 * public 修饰的属性或方法是公有的，可以在任何地方被访问到，默认所有的属性和方法都是 public 的
 * private 修饰的属性或方法是私有的，不能在声明它的类的外部访问
 * protected 修饰的属性或方法是受保护的，它和 private 类似，区别是它在子类中也是允许被访问的
 * 
 **/
class Animal{
	public name;
	public constructor(name){
		this.name = name;
	}
}
let a = new Animal('Jack');
console.log(a.name);    // Jack
a.name = 'Tom';
console.log(a.name);  // Tom
/*
 * 上面的例子中，name 被设置为了 public，所以直接访问实例的 name 属性是允许的。
 * 很多时候，我们希望有的属性是无法直接存取的，这时候就可以用 private 了：
 */
class Animal{
	private name;
	public constructor(name){
		this.name = name;
	}
}
let a = new Animal('Jack');
console.log(a.name);  // Jack
a.name = 'Tom';
// index.ts(9,13): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
// index.ts(10,1): error TS2341: Property 'name' is private and only accessible within class 'Animal'.


//使用 private 修饰的属性或方法，在子类中也是不允许访问的：
class Animal{
	private name;
	public constructor(name){
		this.name = name;
	}
}
class Cat extends Animal{
	constructor(name){
		super(name);
		console.log(this.name);
	}
}
// index.ts(11,17): error TS2341: Property 'name' is private and only accessible within class 'Animal'.

//而如果是用 protected 修饰，则允许在子类中访问：
class Animal {
	protected name;
	public constructor(name) {
		this.name = name;
	}
}

class Cat extends Animal {
	constructor(name) {
		super(name);
		console.log(this.name);
	}
}


/**
 * 抽象类
 * abstract 用于定义抽象类和其中的抽象方法。
 * 抽象类是不允许被实例化的
 * 抽象类中的抽象方法必须被子类实现
 **/
abstract class Animal{
	public name;
	public constructor(name){
		this.name = name;
	}
	public abstract sayHi();
}
class Cat extends Animal{
	public sayHi(){
		console.log(`Meow, My name is ${this.name}`);
	}
}
let cat = new Cat('Tom');



/**
 * 类的类型
 * 给类加上 TypeScript 的类型很简单，与接口类似：
 **/
class Animal{
	name: string;
	constructor(name: string){
		
	}
	sayHi(): string{
		return `My name is ${this.name}`;
	}
}
let a: Animal = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack






















